package com.ubxtech.db.util;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ubxtech.annotation.QueryField;
import com.ubxtech.annotation.QueryType;
import com.ubxtech.core.exception.RRException;
import com.ubxtech.core.req.PageReq;
import com.ubxtech.core.utils.JsonUtils;
import com.ubxtech.core.utils.StrPool;
import lombok.extern.slf4j.Slf4j;

import jakarta.validation.constraints.NotNull;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * @author Victor.Xiao
 * @since 2022-01-14 11:27
 **/
@Slf4j
public class PageBuilderUtil {


    /**
     * 构建分页对象
     * @author Victor.Xiao
     * @since 2022-01-14 15:31
     */
    public static <E> IPage<E> buildPage(PageReq<E> pageReq) {
        E entity = pageReq.getParams();
        if (entity == null ) {
            return buildPage(null,pageReq);
        }
        return buildPage(entity.getClass(),pageReq);
    }

    /**
     * 构建分页对象
     * @author Victor.Xiao
     * @since 2022-01-14 15:31
    */
    public static <E> IPage<E> buildPage(Class<?> entityClazz ,PageReq<?> pageReq) {

        Page<E> page = new Page<>(pageReq.getCurrent(), pageReq.getSize());
        if (entityClazz == null || StrUtil.isEmpty(pageReq.getSortField()) || StrUtil.isEmpty(pageReq.getOrder())) {
            return page;
        }

        List<OrderItem> orders = new ArrayList<>();
        String[] sortArr = StrUtil.splitToArray(pageReq.getSortField(), StrPool.COMMA);
        String[] orderArr = StrUtil.splitToArray(pageReq.getOrder(), StrPool.COMMA);

        int len = Math.min(sortArr.length, orderArr.length);
        for (int i = 0; i < len; i++) {
            String humpSort = sortArr[i];
            // 简单的 驼峰 转 下划线
            String underlineSort = PageBuilderUtil.getDbField(humpSort, entityClazz);
            if (StrUtil.isBlank(underlineSort)) {
                underlineSort = JsonUtils.toUnderlineCase(humpSort);
            }
            orders.add(StrUtil.equalsAny(orderArr[i], "ascending", "ascend", "asc") ? OrderItem.asc(underlineSort) : OrderItem.desc(underlineSort));
        }

        page.setOrders(orders);

        return page;
    }

    /**
     * 构建查询对象
     * @author Victor.Xiao
     * @since 2023-10-25 15:18
     * @param req 查询参数对象
     * @return com.baomidou.mybatisplus.core.conditions.query.QueryWrapper<E>
    */
    public static <E> QueryWrapper<E> buildWrapper(Object req) {
        QueryWrapper<E> queryWrapper = new QueryWrapper<>();
        if (req == null) {
            return queryWrapper;
        }
        try {
            Class<?> beanClass = req.getClass();
            Field[] fields = ReflectUtil.getFields(beanClass);
            if (fields == null || fields.length == 0) {
                return queryWrapper;
            }
            //如果类上有标注,则整个类参数都需处理
            QueryField queryFieldClass = beanClass.getAnnotation(QueryField.class);
            for (Field field : fields) {
                //字段名
                String paramName = field.getName();
                QueryField queryField = field.getAnnotation(QueryField.class);
                //都为空则不处理
                if (queryField == null && queryFieldClass == null) {
                    continue;
                }
                QueryType queryType = QueryType.EQUALS;
                Object value = ReflectUtil.getFieldValue(req, field);
                String column = "";
                if (queryField != null) {
                    queryType = queryField.type();
                    column = queryField.value();
                }
                //如果为空,则驼峰 转 下划线当字段
                if (StrUtil.isBlank(column)) {
                    column = JsonUtils.toUnderlineCase(paramName);
                }
                fillWrapper(queryWrapper, column, queryType, value);

            }
        } catch (Exception e) {
            log.error("生成 wrapper查询对象有误",e);
        }

        return queryWrapper;
    }


    /**
     * 设置参数
     * @author Victor.Xiao
     * @since 2023-10-25 16:40
     * @param wrapper wrapper
     * @param fieldName fieldName
     * @param queryType queryType
     * @param value value
    */
    public static <T> void fillWrapper(QueryWrapper<T> wrapper, String fieldName, QueryType queryType,  Object value) {
        if (wrapper == null || StrUtil.isBlank(fieldName) || queryType == null || value == null || StrUtil.isBlank(value.toString())) {
            return;
        }
        //需要强转成Collection,要不然wrapper的多态会把value当成一个值
        Collection<?> list = null;
        if (value instanceof Collection) {
            list = (List) value;
            if (CollectionUtil.isEmpty(list)) {
                return;
            }
        }
        switch (queryType) {
            case EQUALS:
                wrapper.eq(fieldName, value);
                break;
            case NE:
                wrapper.ne(fieldName, value);
                break;
            case LT:
                wrapper.lt(fieldName, value);
                break;
            case LTE:
                wrapper.le(fieldName, value);
                break;
            case GT:
                wrapper.gt(fieldName, value);
                break;
            case GTE:
                wrapper.ge(fieldName, value);
                break;
            case LIKE_RIGHT:
                wrapper.likeRight(fieldName, value);
                break;
            case NOT_LIKE_RIGHT:
                wrapper.notLike(fieldName, value.toString() + "%");
                break;
            case LIKE:
                wrapper.like(fieldName, value);
                break;
            case NOT_LIKE:
                wrapper.notLike(fieldName, value);
                break;
            case LIKE_LEFT:
                wrapper.likeLeft(fieldName, value);
                break;
            case NOT_LIKE_LEFT:
                wrapper.notLike(fieldName, "%" + value.toString());
                break;
            case IN:
                wrapper.in(fieldName, list);
                break;
            case NOT_IN:
                wrapper.notIn(fieldName, list);
                break;
//            case IS_NULL:
//                wrapper.isNull(fieldName);
//                break;
//            case IS_NOT_NULL:
//                wrapper.isNotNull(fieldName);
//                break;
            default:
                wrapper.eq(fieldName, value);
                break;
        }
    }

    /**
     * 根据 bean字段 反射出 数据库字段
     *
     * @param beanField 字段
     * @param clazz     类型
     * @return 数据库字段名
     */
    public static String getDbField(String beanField, Class<?> clazz) {
        Assert.notNull(clazz, "实体类不能为空");
        Assert.notEmpty(beanField, "字段名不能为空");
        Field field = ReflectUtil.getField(clazz, beanField);
        if (field == null) {
            throw new RRException(StrUtil.format("在类：{}中找不到属性：{}", clazz.getSimpleName(), beanField));
        }

        TableField tf = field.getAnnotation(TableField.class);
        if (tf != null && StrUtil.isNotEmpty(tf.value())) {
            return tf.value();
        }
        TableId ti = field.getAnnotation(TableId.class);
        if (ti != null && StrUtil.isNotEmpty(ti.value())) {
            return ti.value();
        }
        return "";
//        throw new RRException("{}.{} 未标记 @TableField 或 @TableId", clazz.getSimpleName(), beanField);
    }


    /**
     *
     * 转化为本地的Page对象,mybatisplus的page对象会返回多余的字段
     "orders": [],
     "optimizeCountSql": true,
     "searchCount": true,
     "countId": null,
     "maxLimit": null,
     本体的对象没有这些值,3.5mybatisplus也已经标记为Deprecated过时
     *
     * @author Victor.Xiao
     * @since 2023-08-18 10:32
     * @param page page分页对象
     * @param destinationClass 目标类型
     * @return com.ubxtech.core.plugins.Page<T>目录分页对象
    */
    public static <T, E> com.ubxtech.core.plugins.Page<T> toLocalPage(@NotNull IPage<E> page, @NotNull Class<T> destinationClass) {
        if (page == null || destinationClass == null) {
            return null;
        }
        com.ubxtech.core.plugins.Page<T> newPage = new com.ubxtech.core.plugins.Page<>(page.getCurrent(), page.getSize());
        newPage.setPages(page.getPages());
        newPage.setTotal(page.getTotal());

        List<E> list = page.getRecords();
        if (CollUtil.isEmpty(list)) {
            return newPage;
        }

        List<T> destinationList = BeanUtil.copyToList(list, destinationClass);

        newPage.setRecords(destinationList);
        return newPage;
    }

}
